/**
 * 从URL地址中获取指定名称的参数
 * @param {String} key 要在URL地址上获取的参数值  对应的参数名称
 * @returns 
 */
function getUrlParam(key){
    //用于接受获取的结果
    var result;
    //location.search 是查找URL地址上从?问号开始后面的内容，包括问号，所以要用subtr 截取，在把多个参数给分割开
    location.search.substr(1).split('&').forEach(function(item){
        var keyValue = item.split('=');
        //URL地址上的参数是键值对格式，keyValue[0]代表 key =value 中的key,  keyValue[1] 代表 key = value 中的value 是我们要查找的参数值
        if(keyValue[0] == key){
            result = keyValue[1];
        }
    })
    return result;
}

//time 是接口文档里面给的秒数，是距1970年多少秒
function format(time){
    //获取当前时间对象
    let d = new Date();
    //将time秒，*1000 转为毫秒的时间戳，再根据时间戳 .setTime来设置该时间戳对应的年月日
    d.setTime(time*1000);
    return d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate();
}

/**
 * 发送Ajax请求
 * @param {Object} options 发送请求参数，是请求需要的各种信息，集合成一个对象
 */
function ajax(options){
    //1、设置默认的配置信息；当客户端不传参时，有默认的参数可以用
    let config = {
        url:'', //请求地址；求什么？
        type:'get', //请求方式； 请求的语气？
        data:'', //请求额外携带的参数，可以是字符串类型，也可是对象类型。 ；求我时，带不带东西？
        contentType:'application/x-www-form-urlencoded', //设置请求头Content-Type 对应的值；带的东西是如何包装的？
        dataType:'json', //服务端默认响应的数据格式； 要我把你求的东西包装成什么样给你？
        success:function(){} //拿到服务端响应结果后的处理方式，回调函数，用户自己处理； 我把你求的东西给你了，后面你自己处理
    }

    //2、参数合并，客户端传进来的实参和默认的信息选择性合并
    for(let key in config){
        //将默认的config 遍历一遍，key 表示config里每个属性名称
        //短路运算，如果传进来的options里有key 这个属性名称，则options[key]为真，走到右边，覆盖默认的config[key]
        options[key] && (config[key] = options[key]);
    }

    //3、检查合并后的每一个参数是否满足请求的要求

    //3.1  url地址必须传递
    if(!config.url){
        //throw new Error() 抛出错误
        throw new Error('url地址必须传递！');
    }
    //3.2 验证请求方式
    //请求方式分为以下四种，如果传入的请求方式不在四种里，就抛出错误
    let allowType = ['get','post','put','delete'];
    //注意传进来的 大小写问题
    config.type = config.type.toLowerCase();
    if(!allowType.includes(config.type)){
        throw new Error('请求方式设置错误');
    }
    //3.3 验证请求数据，要求请求数据格式只能是字符串或者对象
    let dataType = Object.prototype.toString.call(config.data);
    if(dataType != '[object String]' && dataType != '[object Object]'){
        throw new Error('请求参数的数据格式错误');
    }

    //3.4 验证success 回调函数，要求传进来的必须是函数
    if(Object.prototype.toString.call(config.success) != '[object Function]'){
        throw new Error('success 回调必须是一个函数');
    }

    //4、构建请求携带的数据。 前面验证了传进来的data 参数是否是 字符串或对象；如果是字符串，不做处理，否则就将对象转换为字符串
    let data = ''; //保存请求携带的数据
    if(Object.prototype.toString.call(config.data) == '[object String]'){
        data = config.data;
    }else{
        //如果是get或者delete 请求，携带的参数的格式应该是key = value的字符串格式，要放在URL地址上的
        //如果是post或者put 请求，携带的参数的格式可以是key=value的格式，也可以是JSON格式
        if((config.type == 'post' || config.type == 'put') && (config.contentType == 'application/json')){
            //如果是post/put 请求的JSON格式，就将对象转换为JSON字符串
            data = JSON.stringify(config.data);
        }else{
            //如果是get/delete 请求，就将对象遍历一遍，拼接成key1=value1&key2=value2 的格式
            for(let key in config.data){
                data += `${key} = ${config.data[key]}&`
            }
            //去除最后多的一个&字符串
            data = data.substr(0,data.length-1);
        }
    }

    //5、获取Ajax对象
    let xhr = new XMLHttpRequest;
    //保存请求的地址. 因为如果有传参数data，且是get/delete请求，需要拼接url.
    let url = config.url;
    if((config.type == 'get' || config.type == 'delete') && data){
        url = config.url+'?'+data;
    }

    //打开连接
    xhr.open(config.type,url);

    //设置请求头信息
    //如果传进来的content-type 与默认的配置信息不一致，需要设置
    xhr.setRequestHeader('Content-Type',config.contentType);

    //发送请求
    //判断请求方式为post 或者put，并且data 中有参数需要携带，send里面就要加data，否则就传递空
    xhr.send(((config.type == 'post' || config.type == 'put') && data )?data:'');

    //监听状态改变
    xhr.onreadystatechange = function(){
        if(xhr.status == 200 && xhr.readyState ==4 ){
            //如果服务端返回的数据格式是JSON格式的字符串，就要转换为对象。因为拿到的响应结果要渲染到html上的，所以需要解析JSON格式的数据
            let response = (config.dataType == 'json')?JSON.parse(xhr.responseText):xhr.responseText;

            //拿到响应的结果后，要交给用户（客户端），让他自己决定如何处理这个响应数据
            //使用回调函数处理响应数据,调用传进来的函数，并且，response是作为实参传进去的
            config.success(response);
        }
    }
}


/**
 * 设置cookie
 * @param {String} key cookie的名称
 * @param {String} value cookie的值
 * @param {Number} expires 传递过期时间，单位为秒，默认值0表示关闭浏览器失效
 */
function setCookie(key,value,expires=0){
    if(expires == 0){
        document.cookie = `${key}=${value};path=/`;
    }else{
        let d = new Date();
        d.setTime(d.getTime() - 8*3600*1000 + expires*1000);
        document.cookie = `${key} = ${value};path=/;expires = ${d}`;
    }
}

/**
 * 利用过期时间删除cookie
 * @param {String} key cookie的名称
 */
function removeCookie(key){
    setCookie(key,'',-1);
}




/**
 * 获取cookie的值
 * @param {String} key cookie的名称
 * @returns 
 */
function getCookie(key){
    let value = '';
    document.cookie.split(';').forEach(item=>{
        let keyValue = item.split('=');
        if(key == keyValue[0]){
            value = keyValue[1];
        }
    })
    return value;
}